package com.ruicar.afs.cloud.account.common.send;

import com.alibaba.csp.sentinel.util.StringUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruicar.afs.cloud.account.common.dto.AccountVoucherInfoDto;
import com.ruicar.afs.cloud.account.common.entity.AccountVoucherEntry;
import com.ruicar.afs.cloud.account.common.entity.AccountVoucherInfo;
import com.ruicar.afs.cloud.account.common.processor.constant.VoucherConstant;
import com.ruicar.afs.cloud.account.common.processor.impl.VoucherRequest;
import com.ruicar.afs.cloud.account.common.processor.impl.msg.VoucherSendProcessor;
import com.ruicar.afs.cloud.account.common.service.AccountVoucherEntryService;
import com.ruicar.afs.cloud.account.common.service.AccountVoucherInfoService;
import com.ruicar.afs.cloud.account.common.util.ListSpitUtil;
import com.ruicar.afs.cloud.common.modules.contract.enums.VoucherSendStatus;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * 财务凭证发送service
 */

@Slf4j
@Service
@AllArgsConstructor
@Component
public class VoucherSendService {
    private final AccountVoucherInfoService accountVoucherInfoService;
    private final AccountVoucherEntryService accountVoucherEntryService;
    private final VoucherSendProcessor voucherSendProcessor;
    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(50, 60,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024));

    public void voucherInfoSend() {
        String id = null;

        List<AccountVoucherInfoDto> dtos = new ArrayList<>();
       try {
               IPage iPage = accountVoucherInfoService.page(new Page<>(1, VoucherConstant.querySize),
                            Wrappers.<AccountVoucherInfo>lambdaQuery().eq(AccountVoucherInfo::getStatus, VoucherSendStatus.NOT_SEND)
                                    .gt(StringUtil.isNotBlank(id), AccountVoucherInfo::getId, id).orderByAsc(AccountVoucherInfo::getId));
                    List<AccountVoucherInfo> accountVoucherInfos = iPage.getRecords();
                    if (accountVoucherInfos == null || accountVoucherInfos.size() == 0) {
                        return;
                    }
                    for (AccountVoucherInfo accountVoucherInfo : accountVoucherInfos) {
                        AccountVoucherInfoDto dto = new AccountVoucherInfoDto();
                        dto.setAccountVoucherInfo(accountVoucherInfo);
                        dto.setEntryList(accountVoucherEntryService.list(Wrappers.<AccountVoucherEntry>query().lambda().eq(AccountVoucherEntry::getVoucherNo, accountVoucherInfo.getVoucherNo()).orderByAsc(AccountVoucherEntry::getEntryNo)));
                        dtos.add(dto);
                    }
                if (dtos.size() != 0) {
                    //1.先把数据分批
                    List<List<AccountVoucherInfoDto>> listBatch = ListSpitUtil.splitListToList(dtos, VoucherConstant.batchesSize);
                     this.execute(listBatch);
                    dtos.clear();
                }
            } catch (Exception e) {
                log.error("凭证发送任务执行失败------", e);
            }

    }


    public void execute(List<List<AccountVoucherInfoDto>> listBatch) {
        CountDownLatch countDownLatch = new CountDownLatch(listBatch.size());
        try {
            for (List<AccountVoucherInfoDto> list : listBatch) {
                VoucherRequest request =new VoucherRequest();
                request.setDtos(list);
                EXECUTOR_SERVICE.submit(new VoucherSendRunner(request, voucherSendProcessor, countDownLatch));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error("", e);
            }
        }

    }
    @AllArgsConstructor
    private static class VoucherSendRunner implements Runnable {
        private VoucherRequest request;
        private VoucherSendProcessor voucherSendProcessor;
        private CountDownLatch countDownLatch;
        @Override
        public void run() {
            try {
                voucherSendProcessor.process(request);
            } catch (Exception e) {
                log.error("", e);
            } finally {
                countDownLatch.countDown();
            }
        }
    }
}
